using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Web.UI;

namespace ModWatch
{

	/// <summary>
	/// Provides a base implementation for <see cref="ModWatch.ModWatchExtenderBase"/>
	/// controls that implement <see cref="ModWatch.IModWatcher"/>.
	/// </summary>
	public abstract class ModWatcherExtenderBase : ModWatchExtenderBase, IModWatcher
	{

		#region Properties

		private ModManager _modManager;
		/// <summary>
		/// Gets the <see cref="ModWatch.ModManager"/> contained in the
		/// current <see cref="System.Web.UI.Page"/>.
		/// </summary>
		private ModManager ModManager
		{
			get
			{
				if (_modManager == null)
				{
					IModWatchContainer container = this.Page as IModWatchContainer;
					if (container == null)
						throw new ApplicationException("The page must implement " + typeof(IModWatchContainer).ToString());
					_modManager = container.ModManager;
				}
				return _modManager;
			}
		}

		/// <summary>
		/// Gets or sets the modification group to which the
		/// <see cref="ModWatch.ModWatcherExtenderBase"/> belongs.
		/// </summary>
		[DefaultValue("")]
		public string ModGroup
		{
			get { return GetProperty("ModGroup", ""); }
			set { SetProperty("ModGroup", value); }
		}

		/// <summary>
		/// Gets the <see cref="System.Web.UI.Control"/> that the
		/// <see cref="ModWatch.ModWatcherExtenderBase"/> extends.
		/// </summary>
		protected Control TargetControl
		{
			get { return this.FindControl(base.TargetControlID); }
		}

		/// <summary>
		/// Gets or sets a value indicating whether or not the
		/// value of the TargetControl has yet been saved.
		/// </summary>
		private bool HasBeenSaved
		{
			get { return GetProperty("HasBeenSaved", false); }
			set { SetProperty("HasBeenSaved", value); }
		}

		#endregion

		#region IModWatcher/Abstract Members

		/// <summary>
		/// An abstract method that allows children of the
		/// <see cref="ModWatch.ModWatcherExtenderBase"/>
		/// to determine whether a change has been made the
		/// <see cref="System.Web.UI.Control"/> it is targeting.
		/// </summary>
		/// <returns>true if a change has been detected, false otherwise.</returns>
		protected abstract bool HasBeenChanged();

		/// <summary>
		/// Saves the current value of the <see cref="System.Web.UI.Control"/>
		/// being targeted by this <see cref="ModWatch.ModWatcherExtenderBase"/>.
		/// </summary>
		public abstract void SaveTargetState();

		/// <summary>
		/// See <see cref="ModWatch.IModWatcher.SaveChanges"/>.
		/// </summary>
		public void SaveChanges()
		{
			this.SaveTargetState();
			this.HasBeenSaved = true;
		}

		/// <summary>
		/// Returns a value indicating whether the <see cref="System.Web.UI.Control"/>
		/// being targeted by this <see cref="ModWatch.ModWatcherExtenderBase"/> has changed.
		/// </summary>
		/// <returns>true if a change has been detected, false otherwise.</returns>
		public bool IsDirty()
		{
			if (!this.HasBeenSaved)
				return false;
			else
				return HasBeenChanged();
		}

		#endregion

		#region Overridden Page Methods

		/// <summary>
		/// Raises the <see cref="System.Web.UI.Control.Init"/> event.
		/// </summary>
		/// <param name="e">
		/// An <see cref="System.EventArgs"/>
		/// object that contains event data.
		/// </param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);
			ModManager.ModWatchers.Add(this);

			this.GettingScriptReferences += new EventHandler<ScriptReferencesEventArgs>(this_GettingScriptReferences);
		}

		/// <summary>
		/// Raises the <see cref="System.Web.UI.Control.Unload"/> event.
		/// </summary>
		/// <param name="e">
		/// An <see cref="System.EventArgs"/>
		/// object that contains event data.
		/// </param>
		protected override void OnUnload(EventArgs e)
		{
			ModManager.ModWatchers.Remove(this);
			base.OnUnload(e);
		}

		#endregion

		#region ExtenderControl Implementation

		/// <summary>
		/// Registers the scripts needed by the
		/// <see cref="ModWatch.ModWatcherExtenderBase"/> class.
		/// </summary>
		/// <param name="sender">
		/// The <see cref="System.Object"/> that fired the
		/// <see cref="ModWatch.ModWatchExtenderBase.GettingScriptReferences"/> event.
		/// </param>
		/// <param name="e">
		/// A <see cref="ModWatch.ScriptReferencesEventArgs"/> object that contains the event data.
		/// </param>
		private void this_GettingScriptReferences(object sender, ScriptReferencesEventArgs e)
		{
			e.AddWebResourceScriptReference("ModWatch.Scripts.IModWatcher.js");
			e.AddWebResourceScriptReference("ModWatch.Scripts.ModWatcherBehaviorBase.js");
			e.AddWebResourceScriptReference("ModWatch.Scripts.ModManager.js");
		}

		#endregion

		#region PreRender

		/// <summary>
		/// Raises the <see cref="System.Web.UI.Control.PreRender"/> event.
		/// </summary>
		/// <param name="e">
		/// An <see cref="System.EventArgs"/> object that contains the event data.
		/// </param>
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);

			if (!this.HasBeenSaved)
			{
				this.SaveChanges();
			}
			else if (TargetControl.Visible == false && this.HasBeenChanged())
			{
				// If the control is not visible, then the script descriptors
				// will not be registered, so we need to register any changes
				// with the client's ModManager.

				string registerHiddenChangeScript = "ModWatch.ModManagerInstance.registerHiddenChange();";
				ScriptManager.RegisterStartupScript(this.Page, typeof(ModWatchExtenderBase), "registerHiddenChange", registerHiddenChangeScript, true);
			}
		}

		#endregion

	}

}
